package org.manon.json.meta;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Set;

import org.manon.json.JSONException;
import org.manon.json.annotation.JSonCollection;
import org.manon.json.annotation.JSonSerializer;
import org.manon.json.custom.CustomSerializer;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class MetaPropertyCollection extends MetaProperty{

	private final Class<?> _collectionItem;
	
	private final Class<?> _collectionClass;
	
	@SuppressWarnings("rawtypes")
	private final Class<? extends CustomSerializer> _collectionItemSerializer;
	
	public MetaPropertyCollection(String name, String label, Method method) {
		
		super(MetaPropertyType.COLLECTION,name, label, method);
		
		if (method.getGenericReturnType() instanceof ParameterizedType) {
			_collectionItem = (Class<?>) ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[0];
		} else {
			_collectionItem = Object.class;
		}
		
		JSonCollection jsonCollection = method.getAnnotation(JSonCollection.class);
		
		if (jsonCollection == null) {
			if (Set.class.isAssignableFrom(method.getReturnType())) {
				_collectionClass = java.util.HashSet.class;
			} else if (List.class.isAssignableFrom(method.getReturnType())) {
				_collectionClass = java.util.ArrayList.class;
			} else {
				throw new JSONException("Collection type ["+method.getReturnType() + "] not supported.");
			}
		} else {
			_collectionClass = jsonCollection.collectionImpl();
		}
		
		JSonSerializer serializer = method.getAnnotation(JSonSerializer.class);
		if (serializer != null) {
			_collectionItemSerializer = serializer.impl();
		} else {
			_collectionItemSerializer = null;
		}
	}

	public Class<?> getCollectionItemClass() {
		return _collectionItem;
	}
	
	public Class<?> getCollectionClass() {
		return _collectionClass;
	}
	
	@SuppressWarnings("rawtypes")
	public Class<? extends CustomSerializer> getCollectionItemSerializer() {
		return _collectionItemSerializer;
	}

	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(MetaProperty otherProperty) {
		
		if (otherProperty instanceof MetaPropertyCollection) {
			return getLabel().compareTo(otherProperty.getLabel());
		}
		
		if (otherProperty instanceof MetaPropertySingleValue) {
			return 1;
		}
		
		// other property is a association
		return 1;
	}

	@Override
	public String toString() {
		final StringBuilder builder = new StringBuilder(128);
		builder.append("Property Collection : ");
		toString(builder);
		builder.append(", item=[").append(_collectionItem).append("]");
		builder.append(", class=[").append(_collectionClass).append("]");
		return builder.toString();
	}
	
	/**
	 * @see org.manon.json.meta.MetaProperty#accept(org.manon.json.meta.MetaPropertyVisitor)
	 */
	@Override
	public void accept(MetaPropertyVisitor visitor) {
		visitor.visit(this);
	}
}